package com.cjack.frenchexcel.service;

import com.alibaba.fastjson.JSONObject;
import com.cjack.frenchexcel.config.ErrorCodeDefine;
import com.cjack.frenchexcel.config.LayPage;
import com.cjack.frenchexcel.config.PrivateConfig;
import com.cjack.frenchexcel.dao.EasyEuroDao;
import com.cjack.frenchexcel.dao.RechargeRecordDao;
import com.cjack.frenchexcel.dao.UserAdminDao;
import com.cjack.frenchexcel.enumInfo.DataDefineTypeEnum;
import com.cjack.frenchexcel.exception.CommonException;
import com.cjack.frenchexcel.model.DataDefineModel;
import com.cjack.frenchexcel.model.RechargeExportModel;
import com.cjack.frenchexcel.model.RechargeRecordConditionModel;
import com.cjack.frenchexcel.model.RechargeRecordModel;
import com.cjack.frenchexcel.table.AdminUserTable;
import com.cjack.frenchexcel.table.EasyEuroTable;
import com.cjack.frenchexcel.table.RechargeRecordTable;
import com.cjack.frenchexcel.util.DateFormatUtil;
import com.cjack.frenchexcel.util.FileUtils;
import com.cjack.frenchexcel.util.ModelUtils;
import com.sargeraswang.util.ExcelUtil.ExcelLogs;
import com.sargeraswang.util.ExcelUtil.ExcelUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.io.*;
import java.util.*;

/**
 * Created by root on 10/5/19
 */
@Service
public class RechargeRecordService {

    @Autowired
    private RechargeRecordDao dao;
    @Autowired
    private EasyEuroDao easyEuroDao;
    @Autowired
    private UserAdminDao userAdminDao;
    @Autowired
    private UserAdminService userAdminService;
    @Autowired
    private DataDefineService dataDefineService;

    @Value("${file.upload.baseServerDir}")
    String baseServerDir;
    @Value("${file.upload.baseClientDir}")
    String baseClientDir;
    @Value("${file.upload.spelitor}")
    String spelitor;

    /**
     * @param filePath excel的路径
     * @return 返回因为数据库重复而导入失败的数据
     * @throws CommonException
     * @throws FileNotFoundException
     */
    public JSONObject importFromExcel(String filePath, Long loginUserId) throws CommonException {
        //需要先将 excel的浏览器端访问路径 转化为服务器端访问路径
        filePath = FileUtils.transferClientFileUrl(filePath, baseClientDir, baseServerDir);

        File excelFile = new File(filePath);
        InputStream inputStream = null;
        try {
            inputStream = new FileInputStream(excelFile);
        } catch (FileNotFoundException e) {
            throw new CommonException(ErrorCodeDefine.INTERFACE_COMMON_ERROR, "找不到文件");
        }
        ExcelLogs logs = new ExcelLogs();
        List<RechargeRecordModel> importExcelDatas =
                (List<RechargeRecordModel>) ExcelUtil.importExcel(RechargeRecordModel.class, inputStream, "", logs, 0);
        //过滤掉重复的数据
        List<RechargeRecordModel> repeatDatas = handleRepeat(importExcelDatas);

        List<RechargeRecordModel> saveDatas = new ArrayList<>();
        //批量设置修改/新增时间
        for (RechargeRecordModel importExcelData : importExcelDatas) {
            if (importExcelData.getDealTime() == null) {
                System.out.println("dealTime为空，不处理该条数据");
                continue;
            }
            if (StringUtils.isEmpty(importExcelData.getDealStatus()) || !importExcelData.getDealStatus().equals(
                    "Successful")) {
                throw new CommonException(ErrorCodeDefine.INTERFACE_COMMON_ERROR, "有存在交易状态不为[Successful]的数据，导入失败");
            }
            importExcelData.setDealTimeFrench(DateFormatUtil.format(importExcelData.getDealTime(),
                    DateFormatUtil.DATE_RULE_3));//将中国时间转换成法国时间保存
            importExcelData.setDealTime(DateFormatUtil.frenchTimeToChina(importExcelData.getDealTime()));
            importExcelData.setCreateTime(new Date());
            importExcelData.setUpdateTime(new Date());
            importExcelData.setMoneyStatus("1");
            importExcelData.setImportUserId(loginUserId);
            saveDatas.add(importExcelData);
        }
        dao.save(ModelUtils.copyListModel(saveDatas, RechargeRecordTable.class));
        JSONObject json = new JSONObject();
        json.put("repeatDatas", repeatDatas);
        json.put("successCount", saveDatas.size());
        json.put("errorDatas", logs.getErrorLogList());//返回错误的数据行
        return json;
    }

    public JSONObject exportAsExcel(RechargeRecordConditionModel condition) throws CommonException {

        String exportFileType = "recharExportExcel";
        //先创建excel空文件
        String fileName = FileUtils.getXlsxFileName();
        String dumic = exportFileType + spelitor + FileUtils.getDirByDate();//动态的这一截路径
        //服务器保存文件的目录
        String destDir = baseServerDir + dumic;
        //供浏览器客户端访问的目录
        String clientDir = baseClientDir + dumic;
        //处理目录不存在则创建
        FileUtils.handleDir(destDir);
        File dest = new File(destDir + spelitor + fileName);
        //需要导出的数据
        List<RechargeExportModel> exportDatas = build(this.list(condition));
        //导出的列 title信息
        Map<String, String> col = RechargeExportModel.getColMap();
        OutputStream out;
        try {
            out = new FileOutputStream(dest);
            ExcelUtil.exportExcel(col, exportDatas, out);
            out.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            throw new CommonException(ErrorCodeDefine.INTERFACE_COMMON_ERROR, "导出excel失败");
        } catch (IOException e) {
            e.printStackTrace();
            throw new CommonException(ErrorCodeDefine.INTERFACE_COMMON_ERROR, "导出excel失败");
        }

        //将导出成功的excel地址和导出数据的条数返回给客户端
        JSONObject json = new JSONObject();
        json.put("exportCount", exportDatas.size());
        json.put("filePath", clientDir + spelitor + fileName);
        return json;
    }

    private List<RechargeExportModel> build(List<RechargeRecordModel> datas) {
        List<RechargeExportModel> models = new ArrayList<>();
        for (RechargeRecordModel data : datas) {
            AdminUserTable adminUserTable = userAdminService.get(data.getImportUserId());
            if (adminUserTable != null) {
                data.setJobNumber(adminUserTable.getJobNumber());
            }
            DataDefineModel dataDefineModel =
                    dataDefineService.getByTypeAndKey(DataDefineTypeEnum.RECHARGE_TYPE.name(),
                            data.getRechargeTypeCode());
            data.setRechargeTypeName(dataDefineModel.getDataValue());

            RechargeExportModel model = new RechargeExportModel();
            model.setDealTimeFrench(data.getDealTimeFrench());
            model.setJobNumber(data.getJobNumber());
            model.setMerchantOrderAmount(data.getMerchantOrderAmount());
            model.setRechargeTypeName(data.getRechargeTypeName());
            models.add(model);
        }
        return models;
    }

    public Page<RechargeRecordTable> list(LayPage page, RechargeRecordConditionModel condition) {

        Specification<RechargeRecordTable> specification = handleConditon(condition);

        Sort sort = new Sort(Sort.Direction.DESC, "dealTime");
        Pageable pageable = new PageRequest(page.getPage() - 1, page.getLimit(), sort);
        Page<RechargeRecordTable> resultPage = dao.findAll(specification, pageable);
        return resultPage;
    }

    public Page<EasyEuroTable> listForEasyEuro(LayPage page) {
        Sort sort = new Sort(Sort.Direction.DESC, "dealTime");
        Pageable pageable = new PageRequest(page.getPage() - 1, page.getLimit(), sort);
        Page<EasyEuroTable> resultPage = easyEuroDao.findAll(pageable);
        return resultPage;
    }

    /**
     * 查询condition条件吓的所有数据，除了不分页之外，其它返回结果需要痛表格数据的list接口的一致
     *
     * @param condition
     * @return
     * @throws CommonException
     */
    public List<RechargeRecordModel> list(RechargeRecordConditionModel condition) {

        Specification<RechargeRecordTable> specification = handleConditon(condition);
        Sort sort = new Sort(Sort.Direction.DESC, "id");
        List<RechargeRecordTable> datas = dao.findAll(specification, sort);
        return ModelUtils.copyListModel(datas, RechargeRecordModel.class);
    }

    public void add(RechargeRecordModel model) {
        RechargeRecordTable table;
        if (model.getId() == null) {
            table = ModelUtils.copySignModel(model, RechargeRecordTable.class);
        } else {
            table = dao.findOne(model.getId());
            ModelUtils.copySignModel(model, table);
        }
        dao.save(table);
    }

    public void del(String ids) {
        List<RechargeRecordTable> tables = new ArrayList<>();
        String[] idArr = ids.split(",");
        for (String id : idArr) {
            RechargeRecordTable table = new RechargeRecordTable();
            table.setId(Long.valueOf(id));
            tables.add(table);
        }
        dao.deleteInBatch(tables);
    }

    public List<RechargeRecordModel> listForDay(String moneyStatus) {
        List<RechargeRecordModel> models = new ArrayList<>();
        List<Object[]> datas = null;
        if (moneyStatus.equals("5")) {
            datas = dao.listByDayThree(moneyStatus);
        } else if (moneyStatus.equals("4")) {
            datas = dao.listByDayTwo(moneyStatus);
        } else {
            datas = dao.listByDayOne(moneyStatus);
        }
        for (Object[] data : datas) {
            RechargeRecordModel model = new RechargeRecordModel();
            model.setDealTime(String.valueOf(data[0]));
            model.setUpdateMoneyStatusOne(DateFormatUtil.parse((String) data[0]));
            model.setUpdateMoneyStatusTwo(DateFormatUtil.parse((String) data[0]));
            model.setUpdateMoneyStatusThree(DateFormatUtil.parse((String) data[0]));
            model.setDealTime(String.valueOf(data[0]));
            model.setMerchantOrderAmount(String.valueOf(data[1]));
            models.add(model);
        }
        return models;
    }

    public void setMoneyStatusByDay(String day, String moneyStatus) {
        if (Integer.valueOf(moneyStatus) == 4) {
            dao.setUpdateMoneyStatusDateOne(day, "4");
        } else if (Integer.valueOf(moneyStatus) == 5) {
            dao.setUpdateMoneyStatusDateTwo(day, "5");
        } else if (Integer.valueOf(moneyStatus) == 6) {
            dao.setUpdateMoneyStatusDateThree(day, "6");
        }
    }

    public RechargeRecordTable get(Long id) {
        return dao.getOne(id);
    }

    public RechargeRecordTable queryByOrderNo(String orderNo) {
        List<RechargeRecordTable> tables = dao.getByMerchantOrderNo(orderNo);
        if (tables != null && tables.size() != 0) {
            return tables.get(0);
        }
        return null;
    }

    /**
     * 把重复的数据筛选分离出来
     *
     * @param importExcelDatas
     * @return
     */
    public List<RechargeRecordModel> handleRepeat(List<RechargeRecordModel> importExcelDatas) {
        List<RechargeRecordModel> repeatDatas = new ArrayList<>();
        List<RechargeRecordModel> cycleDatas = new ArrayList<>();
        cycleDatas.addAll(importExcelDatas);
        for (RechargeRecordModel cycleData : cycleDatas) {
            if (isRepeat(cycleData)) {
                importExcelDatas.remove(cycleData);
                repeatDatas.add(cycleData);
            }
        }
        return repeatDatas;
    }

    /**
     * 判断一条数据是否重复
     * 通过 商户订单号来判断
     *
     * @param model
     * @return 返回true代表有重复数据，返回false代表没有重复数据
     */
    private boolean isRepeat(RechargeRecordModel model) {
        List<RechargeRecordTable> tables = dao.getByMerchantOrderNo(model.getMerchantOrderNo());
        if (tables != null && tables.size() > 0) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 组装查询条件
     *
     * @param condition
     * @return
     */
    private Specification<RechargeRecordTable> handleConditon(RechargeRecordConditionModel condition) {
        Specification<RechargeRecordTable> specification = new Specification<RechargeRecordTable>() {
            @Override
            public Predicate toPredicate(Root root, CriteriaQuery query, CriteriaBuilder cb) {
                String month = condition.getDealMonth();
                String startTime = condition.getDealStartTime();
                String endTime = condition.getDealEndTime();

                Predicate predicate = cb.conjunction();
                //组装搜索条件
                if (!StringUtils.isEmpty(condition.getImportUserId())) {
                    //处理多选下拉选择的收银员编号
                    List<String> cashierNumbers = Arrays.asList(condition.getImportUserId().split(","));
                    predicate.getExpressions().add(root.<String>get("importUserId").in(cashierNumbers));
                }
                if (!StringUtils.isEmpty(condition.getPayMoney())) {//模糊搜索
                    predicate.getExpressions().add(cb.like(root.get("merchantOrderAmount").as(String.class),
                            "%" + condition.getPayMoney() + "%"));
                }
                if (!StringUtils.isEmpty(condition.getMerchantOrderNo())) {//模糊搜索
                    predicate.getExpressions().add(cb.like(root.get("merchantOrderNo").as(String.class),
                            condition.getMerchantOrderNo() + "%"));
                }
                if (!StringUtils.isEmpty(condition.getMoneyStatus())) {
                    predicate.getExpressions().add(cb.equal(root.get("moneyStatus").as(String.class),
                            condition.getMoneyStatus()));
                }
                //月份,选了月份，就按照月份的时间来查询
                if (!StringUtils.isEmpty(month)) {
                    Date[] dates = DateFormatUtil.getTimeByMonth(month);
                    //根据今年月份计算起止日期
                    startTime = DateFormatUtil.format(dates[0], DateFormatUtil.DATE_RULE_3);
                    endTime = DateFormatUtil.format(dates[1], DateFormatUtil.DATE_RULE_3);
                }
                //起始日期
                if (!StringUtils.isEmpty(startTime)) {
                    //待定，还不知道搜索哪个类
                    predicate.getExpressions().add(cb.greaterThanOrEqualTo(root.get("dealTimeFrench").as(String.class), startTime));
                }
                //结束日期
                if (!StringUtils.isEmpty(endTime)) {
                    //待定，还不知道搜索哪个类
                    predicate.getExpressions().add(cb.lessThanOrEqualTo(root.get("dealTimeFrench").as(String.class),
                            endTime + " 23:59:59"));
                }
                //只显示最近6个月的数据
                String limitTime = DateFormatUtil.getTimeCountByMonth();
                predicate.getExpressions().add(cb.greaterThanOrEqualTo(root.get("dealTimeFrench").as(String.class),
                        limitTime));

                //判断权限，判断是否有查询所有数据的权限
                AdminUserTable adminUserTable = userAdminDao.findOne(condition.getLoginUserId());
                String roleContent = adminUserTable.getRole().getContent();

                //如果没有上传excel的全息，则是普通员工，通过 collaborateur列查询属于自己消费记录  --11.20取消收银员编号
                if (!PrivateConfig.checkPrivalege(roleContent, PrivateConfig.RECHARGE_LIST_ALL)) {
                    predicate.getExpressions().add(cb.equal(root.get("importUserId").as(Long.class),
                            adminUserTable.getId()));
                }
                if (!StringUtils.isEmpty(condition.getJobNumber())) {
                    List<AdminUserTable> users = userAdminDao.findByJobNumberLike("%" + condition.getJobNumber() + "%");
                    if (users != null && users.size() > 0) {
                        CriteriaBuilder.In<Long> in = cb.in(root.get("importUserId"));
                        for (AdminUserTable user : users) {
                            in.value(user.getId());
                        }
                        predicate.getExpressions().add(in);
                    } else {
                        CriteriaBuilder.In<Long> in = cb.in(root.get("importUserId"));
                        in.value(-1l);
                        predicate.getExpressions().add(in);
                    }
                }
                return predicate;
            }
        };
        return specification;
    }

    /**
     * 统计员工历史已经到账的的充值总额
     *
     * @param adminUserId
     * @return
     */
    public Double sumByMoneyStatusAndAdminUserId(Long adminUserId) {
        Double rechargeTotal = dao.sumByMoneyStatusAndAdminUserId(adminUserId);
        return rechargeTotal;
    }

    /**
     * 统计员工历史的充值总额
     *
     * @param adminUserId
     * @return
     */
    public Double sumByImportUserId(Long adminUserId) {
        Double rechargeTotal = dao.sumByAdminUserId(adminUserId);
        return rechargeTotal;
    }
}
